package com.apestech.api.workflow.lib.element;

import com.apestech.framework.json.JSONArray;
import com.apestech.framework.json.JSONObject;
import org.flowable.bpmn.model.BpmnModel;
import org.flowable.bpmn.model.FlowElement;
import org.flowable.engine.common.impl.interceptor.Command;
import org.flowable.engine.common.impl.interceptor.CommandContext;
import org.flowable.engine.history.HistoricProcessInstance;
import org.flowable.engine.impl.util.ProcessDefinitionUtil;
import org.flowable.engine.runtime.ProcessInstance;
import org.flowable.task.api.Task;
import java.util.List;
import java.util.Map;

/**
 * 用户任务结点配置
 *
 * @author hup
 * @create 2018-07-18-11:10
 */
public class FlowTask {

    private WorkProcessEngine engine;
    private Task task;
    private ProcessInstance processInstance;
    private FlowElement flow;
    private String type;
    private JSONObject input;
    private FlowNodeInfo node;
    private String state;
    private String processInstanceId;
    private String taskId;
    private String parentProcessInstanceId;

    public FlowTask(WorkProcessEngine engine, JSONObject input) throws Exception {
        iniVar(engine, input);
        getTaskInfo();
    }

    public FlowTask(WorkProcessEngine engine, Task task, JSONObject input) throws Exception {
        iniVar(engine, input);
        this.task=task;
        this.processInstanceId=task.getProcessInstanceId();
        processInstance = engine.getRuntimeService().createProcessInstanceQuery().processInstanceId(processInstanceId).singleResult();
    }

    private void iniVar(WorkProcessEngine engine, JSONObject input) throws Exception {
        this.engine=engine;
        this.input=input;
        this.processInstanceId=this.input.getString("processInstanceId");
        this.taskId=this.input.getString("taskId");
        if(this.processInstanceId==null && this.taskId==null){
            throw new Exception("OA流程ID与任务ID至少有一项必填！");
        }
    }

    public String getProcessInstanceId() {
        return processInstanceId;
    }

    private void getTaskInfo() throws Exception {
        parentProcessInstanceId=null;
        if(taskId==null){
            task=engine.getTaskService().createTaskQuery().processInstanceId(processInstanceId).singleResult();
            if(task==null){
                List<ProcessInstance> procs=engine.getRuntimeService().createProcessInstanceQuery().superProcessInstanceId(processInstanceId).list();
                for(ProcessInstance proc : procs){
                    if(!proc.isEnded()){
                        processInstance=proc;
                        parentProcessInstanceId=processInstanceId;
                        break;
                    }
                }
                if(processInstance!=null){
                    task=engine.getTaskService().createTaskQuery().processInstanceId(processInstance.getProcessInstanceId()).singleResult();
                }
            }
        } else {
            task=engine.getTaskService().createTaskQuery().taskId(taskId).singleResult();
        }
        if(task==null){
            return;
            //throw new Exception("该任务结点无效，请检查数据！");
        }
        processInstanceId=task.getProcessInstanceId();
        if(processInstance==null){
            processInstance = engine.getRuntimeService().createProcessInstanceQuery().processInstanceId(processInstanceId).singleResult();
        }
    }

    public void getExecNode() throws Exception {
        flow=getFlow(processInstanceId);
        node= new FlowNodeInfo(flow);
        type=node.getNodeType();
        if("org.flowable.bpmn.model.UserTask".equals(type)){
            if(task.getAssignee()!=null){
                type="claim";   //claim已签收未执行
            } else {
                type="noAssgin";   //noAssgin未赋人员
                FlowQuery query=new FlowQuery(engine);
                if(query.getAssignTaskUser(task.getId())){
                    type="assgin";   //assgin已赋人员未签收
                }
            }
        }
    }

    public void isGatewayConditionCorrect(JSONObject param) throws Exception {
        node.isGatewayConditionCorrect(param);
    }

    public String getNodeType(){
        return node.getNodeType();
    }

    public String getType() {
        return type;
    }

    public JSONArray getNodelist() {
        getState();
        if( "addSign".equals(state) || "counterSign".equals(state) ){
            return null;
        } else{
            return node.getNodelist();
        }
    }

    public Task getTask() {
        return task;
    }

    public void setTask(Task task) {
        this.task = task;
    }

    public ProcessInstance getProcessInstance() {
        return processInstance;
    }

    public String getParentProcessInstanceId() {
        return parentProcessInstanceId;
    }

    public FlowElement getFlow() {
        return flow;
    }

    private FlowElement getFlow(String processInstanceId)throws Exception {
        flow=null;
        if(task!=null) {
            engine.getManagementService().executeCommand(new Command<Void>(){
                @Override
                public Void execute(CommandContext commandContext) {
                    flow=ProcessDefinitionUtil.getProcess(task.getProcessDefinitionId())
                            .getFlowElement(task.getTaskDefinitionKey());
                    return null;
                }
            });
            /*String taskName = task.getTaskDefinitionKey();
            BpmnModel bpmnModel = getBpmnModel(processInstanceId);
            Collection<FlowElement> flowElements = bpmnModel.getProcesses().get(0).getFlowElements();
            for (FlowElement flowElement : flowElements) {
                if (flowElement.getId().equals(taskName)) {
                    return flowElement;
                }
            }*/
        }
        return flow;
    }

    private BpmnModel getBpmnModel(String processInstanceId)throws Exception {
        ProcessInstance runtimeProcessInstance = engine.getRuntimeService().createProcessInstanceQuery().processInstanceId(processInstanceId).singleResult();
        HistoricProcessInstance historicProcessInstance = engine.getHistoryService().createHistoricProcessInstanceQuery().processInstanceId(processInstanceId).singleResult();
        BpmnModel bpmnModel=null;
        if(runtimeProcessInstance != null){
            bpmnModel = engine.getRepositoryService().getBpmnModel(runtimeProcessInstance.getProcessDefinitionId());
        }else if(historicProcessInstance != null) {
            bpmnModel = engine.getRepositoryService().getBpmnModel(historicProcessInstance.getProcessDefinitionId());
        }
        return bpmnModel;
    }

    public void setState(String nodeState){
        state=nodeState;
        Map m=engine.getTaskService().getVariables(task.getId());
        if(m==null){
            m=new JSONObject();
        }
        m.put("oa_state", state);
        engine.getTaskService().setVariables(task.getId(), m);
    }

    public void setStateNull(){
        state=null;
    }

    public String getState(){
        if(state==null){
            Map m=engine.getTaskService().getVariables(task.getId());
            if(m==null){
                setState(type);
                m=engine.getTaskService().getVariables(task.getId());
            }
            if(m.get("oa_state")==null){
                setState(type);
                m=engine.getTaskService().getVariables(task.getId());
            }
            state= (String) m.get("oa_state");
        }
        if("noAssgin".equals(state) || "assgin".equals(state) || "complete".equals(state) ){
            if("claim".equals(type)){
                state=type;
            }
        }
        return state;
    }
}
